Are () needed for string functions too?

Until now it seemed strings and functions that return strings did not need parentheses "()" for string concatenation. In general, it looks less busy when the () is left out -- provided it works.

Here is a case where the behavior is strange:

string dq(string str) {
    return ("\"" str "\"");
}
 
void iThoughtStringFunctionsDidNotNeedParentheses() {
    ack( dq("DOUBLE QUOTED STRING") );
    ack( "Here is a: " dq("DOUBLE QUOTED STRING") " but why is the right quote over here --->" );
    ack( "Here is a: " (dq("DOUBLE QUOTED STRING")) " () needed for string functions too?" );    
}
// call it:
iThoughtStringFunctionsDidNotNeedParentheses();

 


The expected output was:
"DOUBLE QUOTED STRING"
Here is a: "DOUBLE QUOTED STRING" but why is the right quote over here --->
Here is a: "DOUBLE QUOTED STRING" () needed for string functions too?

The actual output was:

"DOUBLE QUOTED STRING"
Here is a: "DOUBLE QUOTED STRING but why is the right quote over here --->"
Here is a: "DOUBLE QUOTED STRING" () needed for string functions too?

The workaround is to put () around string function calls. Is there some phenomenon about string surrounded by double quotes that we should know about?

 


SystemAdmin - Tue May 25 19:53:14 EDT 2010

Re: Are () needed for string functions too?
Peter_Albert - Wed May 26 03:05:38 EDT 2010

This seems to be a known bug (feature?). Citing from Tony Goodman's webpage at smartdxl.com (under "Programming")

Single String Parameter Functions

When the DXL interpreter encounters a function that takes a single string parameter, it ignores the parentheses, thus causing unsuspected results for the unwary programmer. This means that you should not use these functions in-line with other strings as the interpreter will concatentate the string parameter and any following string(s) and then pass the result to the function.

For example, if you run the following DXL
 

string s1 = "one"
string s2 = "two"
print upper(s1) " " s2 "n"


you would expect to get

 

"ONE two"


In fact, you get

 

 

"ONE TWO"


The fix for this is to enclose the function call in parentheses as follows:

 

 

print (upper(s1)) " " s2 "n"



Peter

P.S.: I'd love to post the link, but the insert link button does not work, the once existing sidebar describing the various shortcuts has disappeared. Is this just me and my browser?



 

Re: Are () needed for string functions too?
Mathias Mamsch - Wed May 26 06:11:01 EDT 2010

Citing from the DXL help:

Statement or expression parsing is right associative and has a relatively
high precedence. Parenthesis has the highest precedence.

Left/Right Associativity in a language means, that if you have two operators (in this case concatenation) with the same precendence like A + B - C (+ and - have the same precedence) this can be parsed as (A+B) - C -> left associative or a + (B-C) right associative.

The same is true for concatenation. Telelogic made DXL right associative because it enables you to write something like:
create below current object

which is parsed as:
+create ( below ( Object current() ) )

if you take into account those weird "reverse type casts" of DXL. So this is not a "string function" thing but a general "feature" of DXL. when you use functions with single parameters in another expression you should always code like this:

 

 

 

 

 

 

 

string myString = (name B) " -> " (value B) " and " (someMoreFunction B) "\n"

 


Not:

 

 

 

 

 

 

 

 

string MyString = name(B) " -> " value(B) " and " someMoreFunction(B) "\n"

 


because this only works when B is not concatenable to a string. If B is concatenable to a string then this is parsed as:

 

 

 

 

 

 

 

 

string MyString = name (B " -> " value ( B " and " someMoreFunction ( B "\n" ) ) )

 


due to the right associativity.

Regards, Mathias

 

 

 

 

 

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Re: Are () needed for string functions too?
SystemAdmin - Wed May 26 10:20:37 EDT 2010

Thanks for the explanations.

Understanding the rules now, I'll be sure to use () in concatenation situations for predictable results.

Re: Are () needed for string functions too?
llandale - Wed May 26 16:23:28 EDT 2010

Mathias Mamsch - Wed May 26 06:11:01 EDT 2010

Citing from the DXL help:

Statement or expression parsing is right associative and has a relatively
high precedence. Parenthesis has the highest precedence.

Left/Right Associativity in a language means, that if you have two operators (in this case concatenation) with the same precendence like A + B - C (+ and - have the same precedence) this can be parsed as (A+B) - C -> left associative or a + (B-C) right associative.

The same is true for concatenation. Telelogic made DXL right associative because it enables you to write something like:
create below current object

which is parsed as:
+create ( below ( Object current() ) )

if you take into account those weird "reverse type casts" of DXL. So this is not a "string function" thing but a general "feature" of DXL. when you use functions with single parameters in another expression you should always code like this:

 

 

 

 

 

 

 

string myString = (name B) " -> " (value B) " and " (someMoreFunction B) "\n"

 


Not:

 

 

 

 

 

 

 

 

string MyString = name(B) " -> " value(B) " and " someMoreFunction(B) "\n"

 


because this only works when B is not concatenable to a string. If B is concatenable to a string then this is parsed as:

 

 

 

 

 

 

 

 

string MyString = name (B " -> " value ( B " and " someMoreFunction ( B "\n" ) ) )

 


due to the right associativity.

Regards, Mathias

 

 

 

 

 

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Golly.

string name(int i)    {return i "-int"}
//string name(string s) {return s "-string"}
 
string value(int i)   {return i "-int"}
string someMoreFunction(int i) { return i "-int"}
 
int B = 45
 
string MyString = name(B) " -> " value(B) " and " someMoreFunction(B) " yyy"
print "[" MyString "]\n"
       MyString = name B  " -> " value B  " and " someMoreFunction B  " yyy"
print "[" MyString "]\n"


prints this:
45-int -> 45-int and 45-int yyy
45-int -> 45-int and 45-int yyy

But when you take out the comments at line #2 inserting function 'name(string)', you get this:
45 -> 45-int and 45-int yyy-string]
45 -> 45-int and 45-int yyy-string]

Proving your statement; the overloaded string version of 'name()' gets called last. Using your terminology, in this case 'B' is indeed concatenatable with a string when you add the string version of 'name()'.

That's scary.

But its still a bug. The parenthesis should have precedence over the associativity.

I rarely use this form: function parameter but routinely use this: function(parameter), with maybe a few exceptions. I routinely use empty parens for functions that don't have parameters: m = current(). I may need to review the code for functions invoked on the same line.

 

 

  • Louie

 

 

Re: Are () needed for string functions too?
Mathias Mamsch - Thu May 27 05:07:16 EDT 2010

llandale - Wed May 26 16:23:28 EDT 2010

Golly.

string name(int i)    {return i "-int"}
//string name(string s) {return s "-string"}
 
string value(int i)   {return i "-int"}
string someMoreFunction(int i) { return i "-int"}
 
int B = 45
 
string MyString = name(B) " -> " value(B) " and " someMoreFunction(B) " yyy"
print "[" MyString "]\n"
       MyString = name B  " -> " value B  " and " someMoreFunction B  " yyy"
print "[" MyString "]\n"


prints this:
45-int -> 45-int and 45-int yyy
45-int -> 45-int and 45-int yyy

But when you take out the comments at line #2 inserting function 'name(string)', you get this:
45 -> 45-int and 45-int yyy-string]
45 -> 45-int and 45-int yyy-string]

Proving your statement; the overloaded string version of 'name()' gets called last. Using your terminology, in this case 'B' is indeed concatenatable with a string when you add the string version of 'name()'.

That's scary.

But its still a bug. The parenthesis should have precedence over the associativity.

I rarely use this form: function parameter but routinely use this: function(parameter), with maybe a few exceptions. I routinely use empty parens for functions that don't have parameters: m = current(). I may need to review the code for functions invoked on the same line.

 

 

  • Louie

 

 

I am not sure by what rules exactly the DXL parser will determine if to do the concatenation first or execute the function with the argument. It is not consistent because using my logic an int would be concatenable to a string too

But I don't think that is a bug, because parenthesis have precedence over concatenation. The problem is DXL is a language full of ambiguities and the Parser has a hard time deciding what is what, especially since it does that before even starting the DXL.

The way you use the parentheses is not sufficient: If you do name B A or name (B) A or +name ((B)) A + the result is always the same because the parenthesis only apply to B but not to the ambiguity between concatenation and a function call of name and B. To really use the parentheses for grouping this statement you need to do (name B) A.

DXL developers were obviously trying to be creative when introducing a whitespace as a concatenation operator and additionally making parentheses optional for single argument function calls. Now its to late to change it, therefore DXL programmers need to be aware of the ambiguities and for the sake of not only the parser but also other people trying to read their code they should (imho) do (name B) instead of name(B).

Regards, Mathias

Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS